Libraries


library(here)
library(dplyr)
library(tidyverse)
library(sf)
library(data.table)
library(ggplot2)
library(raster)
library(prismatic)
library(arulesCBA)
library(tibble)

Import data

observations


filenames <- list.files(here("source"),pattern="*.gpkg$")

layers_s = c("09h30_staying","12h30_staying","15h30_staying","18h30_staying")
layers_m = c("09h30_moving","12h30_moving","15h30_moving","18h30_moving")

list_m = list()
list_s = list()

for (i in filenames) {

filename = i  
  
for (j in layers_s) {
df = st_read(here("source",filename),j)
df$fileid = filename
df$layer = j
df = df %>% dplyr::select(-Photo,-mode,-row,-id)
list_s[[length(list_s)+1]]=df
rm(df)
}

for (j in layers_m) {
df = st_read(here("source",filename),j)
df$fileid = paste0(filename,j)
df$fileid = filename
df$layer = j
df = df %>% dplyr::select(-Direction,-Photo)
list_m[[length(list_m)+1]]=df
rm(df)
}

rm(filename)

}

df_s = rbindlist(list_s,use.names = FALSE) %>% st_as_sf()
df_s %>% ggplot() + geom_sf()
df_m = rbindlist(list_m,use.names = FALSE) %>% st_as_sf()
df_m %>% ggplot() + geom_sf()

context


buildings <- read_sf(here("source","geom","context.gpkg"),"buildings")
plot(buildings)
boundary = read_sf(here("source","geom","context.gpkg"),"perimetre") %>% slice(1)
plot(boundary)
zones = read_sf(here("source","geom","context.gpkg"),"zones")
plot(zones)
track = read_sf(here("source","geom","track.gpkg"),"track3")
plot(track)

basemap = stack(here("source","geom","basemap.tif"))
basemap_df = as.data.frame(basemap, xy= TRUE)
basemap_df = 
  basemap_df %>% 
  rename(red = basemap_1, #Rename bands
         green = basemap_2,
         blue = basemap_3) %>%
  filter(red != 0) #drop data w/o rgb information

map = stack(here("source","geom","map_georeferenced_clip.tif"))
map_df = as.data.frame(map, xy= TRUE)
map_df = 
  map_df %>% 
  rename(red = map_georeferenced_clip_1, #Rename bands
         green = map_georeferenced_clip_2,
         blue = map_georeferenced_clip_3) %>%
  filter(red != 0) #drop data w/o rgb information

bbox <- st_bbox(st_buffer(boundary,dist = 5, joinStyle="ROUND")) #global

#Data organisation

IDs


#survey_id
df_s$survey_id <- paste0(substr(df_s$path,start=76,stop=81),"_",substr(df_s$path,start=83,stop=87))
df_s$survey_id<-gsub("-","",df_s$survey_id)
df_s$survey_id<-gsub("_","",df_s$survey_id)

df_m$survey_id <- paste0(substr(df_m$path,start=76,stop=81),"_",substr(df_m$path,start=83,stop=87))
df_m$survey_id<-gsub("-","",df_m$survey_id)
df_m$survey_id<-gsub("_","",df_m$survey_id)

# row_id
df_s$row_id <- paste(df_s$survey_id, ave(df_s$id,df_s$survey_id, FUN = seq_along), sep="")
Error in split.default(x, g) : first argument must be a vector

Means & totals



# Row_total
df_s$row_total <- df_s$gender_male+df_s$gender_female
df_m$row_total <- df_m$gender_male+df_m$gender_female

# Mean age per group
df_s$age_mean <- round(((df_s$age_0.14*7)+(df_s$age_15.24*19.5)+(df_s$age_25.44*34.5)+
                                (df_s$age_45.64*54.5)+(df_s$age_65.74*69.5)+
                                (df_s$age_75p*80))/df_s$row_total,digits = 1)

df_m$age_mean <- round(((df_m$age_0.14*7)+(df_m$age_15.24*19.5)+(df_m$age_25.44*34.5)+
                                (df_m$age_45.64*54.5)+(df_m$age_65.74*69.5)+
                                (df_m$age_75p*80))/df_m$row_total,digits = 1)

Separating columns of time & date from timestamp

df_s$timestamp <- gsub('T',' ',df_s$timestamp)
df_s$timestamp <- substr(df_s$timestamp,start=1,stop=19)
df_s$date <- format(as.POSIXct(strptime(df_s$timestamp,"%Y-%m-%d",tz="")),format = "%Y-%m-%d") # separate date column
df_s$time <- format(as.POSIXct(strptime(df_s$timestamp,"%Y-%m-%d %H:%M:%S",tz="")) ,format = "%H:%M:%S") # separate time column

df_m$timestamp <- gsub('T',' ',df_m$timestamp)
df_m$timestamp <- substr(df_m$timestamp,start=1,stop=19)
df_m$date <- format(as.POSIXct(strptime(df_m$timestamp,"%Y-%m-%d",tz="")),format = "%Y-%m-%d") # separate date column
df_m$time <- format(as.POSIXct(strptime(df_m$timestamp,"%Y-%m-%d %H:%M:%S",tz="")) ,format = "%H:%M:%S") # separate time column

Adding coordinates WGS84

library(sf)

#conversion of points into spatial feature object 
df_s_lb93 <- st_as_sf(df_s, coords = c("X_lb93", "Y_lb93"), crs = 2154, agr = "constant", remove = FALSE)
  
#conversion of Lambert93 coordinates into pseudo mercator (WGS84, EPSg 3857) for kepler.gl
df_s_wgs84 <- st_transform(df_s_lb93, 4326)
  
#extracting X and Y coordinates from geometry
df_s_xy_wgs84 <- st_coordinates(df_s_wgs84)
  
#replacing longitude and latitude by X and Y respectively
df_s$X_wgs84 <- df_s_xy_wgs84[,1]
df_s$Y_wgs84 <- df_s_xy_wgs84[,2]

Reorder dataframe

s.df <- df_s[,c("survey_id","row_id","timestamp","date","time","tc","X_lb93","Y_lb93","X_wgs84","Y_wgs84",
                      "row_total","gender_male","gender_female","age_mean","age_0_7", "age_8_17","age_18_34","age_35_50","age_51_64","age_65",
                      "posture","engagement","clothing","exposure","activity","mode","stay_time")]

m.df <- df_m[,c("survey_id","row_id","timestamp","date","time","tc",
                      "row_total","gender_male","gender_female","age_mean", "age_0_7", "age_8_17","age_18_34","age_35_50","age_51_64","age_65",
                      "engagement","clothing","exposure","mouvement","mode")]

Spatial aggregation

mesh


grid = 
  st_make_grid(
    boundary,
    cellsize = 7,
    square = FALSE) %>% 
  st_sf() %>% 
  st_cast %>%
  mutate(
    id = 1:n())

grid = grid %>%
  mutate(
    int = st_intersects(grid,boundary, sparse = F)
    ) %>%
  filter(int == T) %>%
  dplyr::select(-int)
  
plot(grid)

aggregation

hexbin_s =
  st_join(
    grid,
    df_s %>% filter(row_total != 0),
    left = FALSE,
    join = st_intersects) %>%
  group_by(id,fileid) %>%
  summarise(
    n = n(),
    nbp = sum(row_total),
    gender_male = sum(gender_male),
    gender_female = sum(gender_female))
`summarise()` has grouped output by 'id'. You can override using the `.groups` argument.
hexbin_m =
  st_join(
    grid,
    df_m %>% filter(row_total != 0),
    left = FALSE,
    join = st_intersects) %>%
  group_by(id,fileid) %>%
  summarise(
    n = n(),
    nbp = sum(row_total),
    gender_male = sum(gender_male),
    gender_female = sum(gender_female))
`summarise()` has grouped output by 'id'. You can override using the `.groups` argument.

Plot


theme_carto <-
  theme_bw() +
  theme(
    #axis.line=element_blank(),
    axis.text.x=element_blank(),
    axis.text.y=element_blank(),
    axis.ticks=element_blank(),
    axis.title.x=element_blank(),
    axis.title.y=element_blank(),
    #legend.position="none",
    panel.background=element_blank(),
    #panel.border=element_blank(),
    panel.grid.major=element_blank(),
    panel.grid.minor=element_blank(),
    plot.background=element_blank()
    )

bck =
  ggplot() +
  geom_raster(
    data = basemap_df, aes(x = x, y =y), fill = rgb(r = basemap_df$red, g = basemap_df$green, b = basemap_df$blue, maxColorValue = 255),
    show.legend = FALSE)+
  geom_raster(
    data = map_df, aes(x = x, y =y), fill = rgb(r = map_df$red, g = map_df$green, b = map_df$blue, maxColorValue = 255),
    show.legend = FALSE)

bck +
#ggplot()+
  geom_sf(data=buildings, color = gray(0.5),size = 0.4)+
  geom_sf(data=df_s, alpha = 0.2, color = "red")+
  geom_sf(data=df_m, alpha = 0.2, color = "blue")+
  geom_sf(data=zones, alpha = 1, color = "red",fill = NA, lty = 2, lwd = 5)+
  xlim(bbox[["xmin"]],bbox[["xmax"]])+
  ylim(bbox[["ymin"]],bbox[["ymax"]])+
  theme_carto

ggsave(here("outcomes","all.jpg"))
Saving 7.16 x 4.42 in image

bck +
#ggplot()+  
  geom_sf(data=grid, color = gray(0.5),size = 0.1, fill = NA)+
  geom_sf(data=buildings, color = gray(0.5),size = 0.4)+
  geom_sf(data=hexbin_s, aes(fill = nbp,alpha = nbp))+
  #geom_sf(data=df_m, alpha = 0.2, color = "blue")+
  xlim(bbox[["xmin"]],bbox[["xmax"]])+
  ylim(bbox[["ymin"]],bbox[["ymax"]])+
  theme_carto

ggsave(here("outcomes","hex_staying.jpg"))
Saving 7.16 x 4.42 in image

bck +
#ggplot()+  
  geom_sf(data=grid, color = gray(0.5),size = 0.1, fill = NA)+
  geom_sf(data=buildings, color = gray(0.5),size = 0.4)+
  geom_sf(data=hexbin_m, aes(fill = nbp, alpha = nbp))+
  #geom_sf(data=df_m, alpha = 0.2, color = "blue")+
  xlim(bbox[["xmin"]],bbox[["xmax"]])+
  ylim(bbox[["ymin"]],bbox[["ymax"]])+
  theme_carto

ggsave(here("outcomes","hex_moving.jpg"))
Saving 7.16 x 4.42 in image

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBMaWJyYXJpZXMKYGBge3J9CgpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShyYXN0ZXIpCmxpYnJhcnkocHJpc21hdGljKQpsaWJyYXJ5KGFydWxlc0NCQSkKbGlicmFyeSh0aWJibGUpCgpgYGAKCgojIEltcG9ydCBkYXRhCgojIyBvYnNlcnZhdGlvbnMKYGBge3J9CgpmaWxlbmFtZXMgPC0gbGlzdC5maWxlcyhoZXJlKCJzb3VyY2UiKSxwYXR0ZXJuPSIqLmdwa2ckIikKCmxheWVyc19zID0gYygiMDloMzBfc3RheWluZyIsIjEyaDMwX3N0YXlpbmciLCIxNWgzMF9zdGF5aW5nIiwiMThoMzBfc3RheWluZyIpCmxheWVyc19tID0gYygiMDloMzBfbW92aW5nIiwiMTJoMzBfbW92aW5nIiwiMTVoMzBfbW92aW5nIiwiMThoMzBfbW92aW5nIikKCmxpc3RfbSA9IGxpc3QoKQpsaXN0X3MgPSBsaXN0KCkKCmZvciAoaSBpbiBmaWxlbmFtZXMpIHsKCmZpbGVuYW1lID0gaSAgCiAgCmZvciAoaiBpbiBsYXllcnNfcykgewpkZiA9IHN0X3JlYWQoaGVyZSgic291cmNlIixmaWxlbmFtZSksaikKZGYkZmlsZWlkID0gZmlsZW5hbWUKZGYkbGF5ZXIgPSBqCmRmID0gZGYgJT4lIGRwbHlyOjpzZWxlY3QoLVBob3RvLC1tb2RlLC1yb3csLWlkKQpsaXN0X3NbW2xlbmd0aChsaXN0X3MpKzFdXT1kZgpybShkZikKfQoKZm9yIChqIGluIGxheWVyc19tKSB7CmRmID0gc3RfcmVhZChoZXJlKCJzb3VyY2UiLGZpbGVuYW1lKSxqKQpkZiRmaWxlaWQgPSBwYXN0ZTAoZmlsZW5hbWUsaikKZGYkZmlsZWlkID0gZmlsZW5hbWUKZGYkbGF5ZXIgPSBqCmRmID0gZGYgJT4lIGRwbHlyOjpzZWxlY3QoLURpcmVjdGlvbiwtUGhvdG8pCmxpc3RfbVtbbGVuZ3RoKGxpc3RfbSkrMV1dPWRmCnJtKGRmKQp9CgpybShmaWxlbmFtZSkKCn0KCmRmX3MgPSByYmluZGxpc3QobGlzdF9zLHVzZS5uYW1lcyA9IEZBTFNFKSAlPiUgc3RfYXNfc2YoKQpkZl9zICU+JSBnZ3Bsb3QoKSArIGdlb21fc2YoKQpkZl9tID0gcmJpbmRsaXN0KGxpc3RfbSx1c2UubmFtZXMgPSBGQUxTRSkgJT4lIHN0X2FzX3NmKCkKZGZfbSAlPiUgZ2dwbG90KCkgKyBnZW9tX3NmKCkKCmBgYAoKIyMgY29udGV4dApgYGB7cn0KCmJ1aWxkaW5ncyA8LSByZWFkX3NmKGhlcmUoInNvdXJjZSIsImdlb20iLCJjb250ZXh0Lmdwa2ciKSwiYnVpbGRpbmdzIikKcGxvdChidWlsZGluZ3MpCmJvdW5kYXJ5ID0gcmVhZF9zZihoZXJlKCJzb3VyY2UiLCJnZW9tIiwiY29udGV4dC5ncGtnIiksInBlcmltZXRyZSIpICU+JSBzbGljZSgxKQpwbG90KGJvdW5kYXJ5KQp6b25lcyA9IHJlYWRfc2YoaGVyZSgic291cmNlIiwiZ2VvbSIsImNvbnRleHQuZ3BrZyIpLCJ6b25lcyIpCnBsb3Qoem9uZXMpCnRyYWNrID0gcmVhZF9zZihoZXJlKCJzb3VyY2UiLCJnZW9tIiwidHJhY2suZ3BrZyIpLCJ0cmFjazMiKQpwbG90KHRyYWNrKQoKYmFzZW1hcCA9IHN0YWNrKGhlcmUoInNvdXJjZSIsImdlb20iLCJiYXNlbWFwLnRpZiIpKQpiYXNlbWFwX2RmID0gYXMuZGF0YS5mcmFtZShiYXNlbWFwLCB4eT0gVFJVRSkKYmFzZW1hcF9kZiA9IAogIGJhc2VtYXBfZGYgJT4lIAogIHJlbmFtZShyZWQgPSBiYXNlbWFwXzEsICNSZW5hbWUgYmFuZHMKICAgICAgICAgZ3JlZW4gPSBiYXNlbWFwXzIsCiAgICAgICAgIGJsdWUgPSBiYXNlbWFwXzMpICU+JQogIGZpbHRlcihyZWQgIT0gMCkgI2Ryb3AgZGF0YSB3L28gcmdiIGluZm9ybWF0aW9uCgptYXAgPSBzdGFjayhoZXJlKCJzb3VyY2UiLCJnZW9tIiwibWFwX2dlb3JlZmVyZW5jZWRfY2xpcC50aWYiKSkKbWFwX2RmID0gYXMuZGF0YS5mcmFtZShtYXAsIHh5PSBUUlVFKQptYXBfZGYgPSAKICBtYXBfZGYgJT4lIAogIHJlbmFtZShyZWQgPSBtYXBfZ2VvcmVmZXJlbmNlZF9jbGlwXzEsICNSZW5hbWUgYmFuZHMKICAgICAgICAgZ3JlZW4gPSBtYXBfZ2VvcmVmZXJlbmNlZF9jbGlwXzIsCiAgICAgICAgIGJsdWUgPSBtYXBfZ2VvcmVmZXJlbmNlZF9jbGlwXzMpICU+JQogIGZpbHRlcihyZWQgIT0gMCkgI2Ryb3AgZGF0YSB3L28gcmdiIGluZm9ybWF0aW9uCgpiYm94IDwtIHN0X2Jib3goc3RfYnVmZmVyKGJvdW5kYXJ5LGRpc3QgPSA1LCBqb2luU3R5bGU9IlJPVU5EIikpICNnbG9iYWwKCmBgYAoKI0RhdGEgb3JnYW5pc2F0aW9uCgojIyBJRHMKYGBge3J9Cgojc3VydmV5X2lkCmRmX3Mkc3VydmV5X2lkIDwtIHBhc3RlMChzdWJzdHIoZGZfcyRwYXRoLHN0YXJ0PTc2LHN0b3A9ODEpLCJfIixzdWJzdHIoZGZfcyRwYXRoLHN0YXJ0PTgzLHN0b3A9ODcpKQpkZl9zJHN1cnZleV9pZDwtZ3N1YigiLSIsIiIsZGZfcyRzdXJ2ZXlfaWQpCmRmX3Mkc3VydmV5X2lkPC1nc3ViKCJfIiwiIixkZl9zJHN1cnZleV9pZCkKCmRmX20kc3VydmV5X2lkIDwtIHBhc3RlMChzdWJzdHIoZGZfbSRwYXRoLHN0YXJ0PTc2LHN0b3A9ODEpLCJfIixzdWJzdHIoZGZfbSRwYXRoLHN0YXJ0PTgzLHN0b3A9ODcpKQpkZl9tJHN1cnZleV9pZDwtZ3N1YigiLSIsIiIsZGZfbSRzdXJ2ZXlfaWQpCmRmX20kc3VydmV5X2lkPC1nc3ViKCJfIiwiIixkZl9tJHN1cnZleV9pZCkKCiMgcm93X2lkCmRmX3Mkcm93X2lkIDwtIHBhc3RlKGRmX3Mkc3VydmV5X2lkLCBhdmUoZGZfcyRpZCxkZl9zJHN1cnZleV9pZCwgRlVOID0gc2VxX2Fsb25nKSwgc2VwPSIiKQpkZl9tJHJvd19pZCA8LSBwYXN0ZShkZl9tJHN1cnZleV9pZCwgYXZlKGRmX20kaWQsZGZfbSRzdXJ2ZXlfaWQsIEZVTiA9IHNlcV9hbG9uZyksIHNlcD0iIikKCiN0YwpkZl9zJHRjIDwtIHN1YnN0cihkZl9zJHBhdGgsc3RhcnQ9ODMsc3RvcD04NykKZGZfcyR0YzwtZ3N1YigiLSIsIjoiLGRmX3MkdGMpCmRmX20kdGMgPC0gc3Vic3RyKGRmX20kcGF0aCxzdGFydD04MyxzdG9wPTg3KQpkZl9tJHRjPC1nc3ViKCItIiwiOiIsZGZfbSR0YykKCmBgYAoKIyMgTWVhbnMgJiB0b3RhbHMKYGBge3J9CgojIFJvd190b3RhbApkZl9zJHJvd190b3RhbCA8LSBkZl9zJGdlbmRlcl9tYWxlK2RmX3MkZ2VuZGVyX2ZlbWFsZQpkZl9tJHJvd190b3RhbCA8LSBkZl9tJGdlbmRlcl9tYWxlK2RmX20kZ2VuZGVyX2ZlbWFsZQoKIyBNZWFuIGFnZSBwZXIgZ3JvdXAKZGZfcyRhZ2VfbWVhbiA8LSByb3VuZCgoKGRmX3MkYWdlXzAuMTQqNykrKGRmX3MkYWdlXzE1LjI0KjE5LjUpKyhkZl9zJGFnZV8yNS40NCozNC41KSsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZGZfcyRhZ2VfNDUuNjQqNTQuNSkrKGRmX3MkYWdlXzY1Ljc0KjY5LjUpKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkZl9zJGFnZV83NXAqODApKS9kZl9zJHJvd190b3RhbCxkaWdpdHMgPSAxKQoKZGZfbSRhZ2VfbWVhbiA8LSByb3VuZCgoKGRmX20kYWdlXzAuMTQqNykrKGRmX20kYWdlXzE1LjI0KjE5LjUpKyhkZl9tJGFnZV8yNS40NCozNC41KSsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZGZfbSRhZ2VfNDUuNjQqNTQuNSkrKGRmX20kYWdlXzY1Ljc0KjY5LjUpKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkZl9tJGFnZV83NXAqODApKS9kZl9tJHJvd190b3RhbCxkaWdpdHMgPSAxKQoKYGBgCgoKIyMgU2VwYXJhdGluZyBjb2x1bW5zIG9mIHRpbWUgJiBkYXRlIGZyb20gdGltZXN0YW1wCmBgYHtyfQpkZl9zJHRpbWVzdGFtcCA8LSBnc3ViKCdUJywnICcsZGZfcyR0aW1lc3RhbXApCmRmX3MkdGltZXN0YW1wIDwtIHN1YnN0cihkZl9zJHRpbWVzdGFtcCxzdGFydD0xLHN0b3A9MTkpCmRmX3MkZGF0ZSA8LSBmb3JtYXQoYXMuUE9TSVhjdChzdHJwdGltZShkZl9zJHRpbWVzdGFtcCwiJVktJW0tJWQiLHR6PSIiKSksZm9ybWF0ID0gIiVZLSVtLSVkIikgIyBzZXBhcmF0ZSBkYXRlIGNvbHVtbgpkZl9zJHRpbWUgPC0gZm9ybWF0KGFzLlBPU0lYY3Qoc3RycHRpbWUoZGZfcyR0aW1lc3RhbXAsIiVZLSVtLSVkICVIOiVNOiVTIix0ej0iIikpICxmb3JtYXQgPSAiJUg6JU06JVMiKSAjIHNlcGFyYXRlIHRpbWUgY29sdW1uCgpkZl9tJHRpbWVzdGFtcCA8LSBnc3ViKCdUJywnICcsZGZfbSR0aW1lc3RhbXApCmRmX20kdGltZXN0YW1wIDwtIHN1YnN0cihkZl9tJHRpbWVzdGFtcCxzdGFydD0xLHN0b3A9MTkpCmRmX20kZGF0ZSA8LSBmb3JtYXQoYXMuUE9TSVhjdChzdHJwdGltZShkZl9tJHRpbWVzdGFtcCwiJVktJW0tJWQiLHR6PSIiKSksZm9ybWF0ID0gIiVZLSVtLSVkIikgIyBzZXBhcmF0ZSBkYXRlIGNvbHVtbgpkZl9tJHRpbWUgPC0gZm9ybWF0KGFzLlBPU0lYY3Qoc3RycHRpbWUoZGZfbSR0aW1lc3RhbXAsIiVZLSVtLSVkICVIOiVNOiVTIix0ej0iIikpICxmb3JtYXQgPSAiJUg6JU06JVMiKSAjIHNlcGFyYXRlIHRpbWUgY29sdW1uCmBgYAoKCiMjIEFkZGluZyBjb29yZGluYXRlcyBXR1M4NApgYGB7cn0KbGlicmFyeShzZikKCiNjb252ZXJzaW9uIG9mIHBvaW50cyBpbnRvIHNwYXRpYWwgZmVhdHVyZSBvYmplY3QgCmRmX3NfbGI5MyA8LSBzdF9hc19zZihkZl9zLCBjb29yZHMgPSBjKCJYX2xiOTMiLCAiWV9sYjkzIiksIGNycyA9IDIxNTQsIGFnciA9ICJjb25zdGFudCIsIHJlbW92ZSA9IEZBTFNFKQogIAojY29udmVyc2lvbiBvZiBMYW1iZXJ0OTMgY29vcmRpbmF0ZXMgaW50byBwc2V1ZG8gbWVyY2F0b3IgKFdHUzg0LCBFUFNnIDM4NTcpIGZvciBrZXBsZXIuZ2wKZGZfc193Z3M4NCA8LSBzdF90cmFuc2Zvcm0oZGZfc19sYjkzLCA0MzI2KQogIAojZXh0cmFjdGluZyBYIGFuZCBZIGNvb3JkaW5hdGVzIGZyb20gZ2VvbWV0cnkKZGZfc194eV93Z3M4NCA8LSBzdF9jb29yZGluYXRlcyhkZl9zX3dnczg0KQogIAojcmVwbGFjaW5nIGxvbmdpdHVkZSBhbmQgbGF0aXR1ZGUgYnkgWCBhbmQgWSByZXNwZWN0aXZlbHkKZGZfcyRYX3dnczg0IDwtIGRmX3NfeHlfd2dzODRbLDFdCmRmX3MkWV93Z3M4NCA8LSBkZl9zX3h5X3dnczg0WywyXQoKYGBgCgojIyBSZW9yZGVyIGRhdGFmcmFtZQpgYGB7cn0Kcy5kZiA8LSBkZl9zWyxjKCJzdXJ2ZXlfaWQiLCJyb3dfaWQiLCJ0aW1lc3RhbXAiLCJkYXRlIiwidGltZSIsInRjIiwiWF9sYjkzIiwiWV9sYjkzIiwiWF93Z3M4NCIsIllfd2dzODQiLAogICAgICAgICAgICAgICAgICAgICAgInJvd190b3RhbCIsImdlbmRlcl9tYWxlIiwiZ2VuZGVyX2ZlbWFsZSIsImFnZV9tZWFuIiwiYWdlXzBfNyIsICJhZ2VfOF8xNyIsImFnZV8xOF8zNCIsImFnZV8zNV81MCIsImFnZV81MV82NCIsImFnZV82NSIsCiAgICAgICAgICAgICAgICAgICAgICAicG9zdHVyZSIsImVuZ2FnZW1lbnQiLCJjbG90aGluZyIsImV4cG9zdXJlIiwiYWN0aXZpdHkiLCJtb2RlIiwic3RheV90aW1lIildCgptLmRmIDwtIGRmX21bLGMoInN1cnZleV9pZCIsInJvd19pZCIsInRpbWVzdGFtcCIsImRhdGUiLCJ0aW1lIiwidGMiLAogICAgICAgICAgICAgICAgICAgICAgInJvd190b3RhbCIsImdlbmRlcl9tYWxlIiwiZ2VuZGVyX2ZlbWFsZSIsImFnZV9tZWFuIiwgImFnZV8wXzciLCAiYWdlXzhfMTciLCJhZ2VfMThfMzQiLCJhZ2VfMzVfNTAiLCJhZ2VfNTFfNjQiLCJhZ2VfNjUiLAogICAgICAgICAgICAgICAgICAgICAgImVuZ2FnZW1lbnQiLCJjbG90aGluZyIsImV4cG9zdXJlIiwibW91dmVtZW50IiwibW9kZSIpXQpgYGAKCgojIFNwYXRpYWwgYWdncmVnYXRpb24KCiMjIG1lc2gKYGBge3J9CgpncmlkID0gCiAgc3RfbWFrZV9ncmlkKAogICAgYm91bmRhcnksCiAgICBjZWxsc2l6ZSA9IDcsCiAgICBzcXVhcmUgPSBGQUxTRSkgJT4lIAogIHN0X3NmKCkgJT4lIAogIHN0X2Nhc3QgJT4lCiAgbXV0YXRlKAogICAgaWQgPSAxOm4oKSkKCmdyaWQgPSBncmlkICU+JQogIG11dGF0ZSgKICAgIGludCA9IHN0X2ludGVyc2VjdHMoZ3JpZCxib3VuZGFyeSwgc3BhcnNlID0gRikKICAgICkgJT4lCiAgZmlsdGVyKGludCA9PSBUKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1pbnQpCiAgCnBsb3QoZ3JpZCkKCmBgYAoKCiMjIGFnZ3JlZ2F0aW9uCmBgYHtyfQpoZXhiaW5fcyA9CiAgc3Rfam9pbigKICAgIGdyaWQsCiAgICBkZl9zICU+JSBmaWx0ZXIocm93X3RvdGFsICE9IDApLAogICAgbGVmdCA9IEZBTFNFLAogICAgam9pbiA9IHN0X2ludGVyc2VjdHMpICU+JQogIGdyb3VwX2J5KGlkLGZpbGVpZCkgJT4lCiAgc3VtbWFyaXNlKAogICAgbiA9IG4oKSwKICAgIG5icCA9IHN1bShyb3dfdG90YWwpLAogICAgZ2VuZGVyX21hbGUgPSBzdW0oZ2VuZGVyX21hbGUpLAogICAgZ2VuZGVyX2ZlbWFsZSA9IHN1bShnZW5kZXJfZmVtYWxlKSkKCmhleGJpbl9tID0KICBzdF9qb2luKAogICAgZ3JpZCwKICAgIGRmX20gJT4lIGZpbHRlcihyb3dfdG90YWwgIT0gMCksCiAgICBsZWZ0ID0gRkFMU0UsCiAgICBqb2luID0gc3RfaW50ZXJzZWN0cykgJT4lCiAgZ3JvdXBfYnkoaWQsZmlsZWlkKSAlPiUKICBzdW1tYXJpc2UoCiAgICBuID0gbigpLAogICAgbmJwID0gc3VtKHJvd190b3RhbCksCiAgICBnZW5kZXJfbWFsZSA9IHN1bShnZW5kZXJfbWFsZSksCiAgICBnZW5kZXJfZmVtYWxlID0gc3VtKGdlbmRlcl9mZW1hbGUpKQoKYGBgCgoKIyBQbG90CgpgYGB7cn0KCnRoZW1lX2NhcnRvIDwtCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICAjYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAjbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLAogICAgI3BhbmVsLmJvcmRlcj1lbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpLAogICAgcGxvdC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKQogICAgKQoKYGBgCgoKYGBge3J9CgpiY2sgPQogIGdncGxvdCgpICsKICBnZW9tX3Jhc3RlcigKICAgIGRhdGEgPSBiYXNlbWFwX2RmLCBhZXMoeCA9IHgsIHkgPXkpLCBmaWxsID0gcmdiKHIgPSBiYXNlbWFwX2RmJHJlZCwgZyA9IGJhc2VtYXBfZGYkZ3JlZW4sIGIgPSBiYXNlbWFwX2RmJGJsdWUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkrCiAgZ2VvbV9yYXN0ZXIoCiAgICBkYXRhID0gbWFwX2RmLCBhZXMoeCA9IHgsIHkgPXkpLCBmaWxsID0gcmdiKHIgPSBtYXBfZGYkcmVkLCBnID0gbWFwX2RmJGdyZWVuLCBiID0gbWFwX2RmJGJsdWUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkKCmJjayArCiNnZ3Bsb3QoKSsKICBnZW9tX3NmKGRhdGE9YnVpbGRpbmdzLCBjb2xvciA9IGdyYXkoMC41KSxzaXplID0gMC40KSsKICBnZW9tX3NmKGRhdGE9ZGZfcywgYWxwaGEgPSAwLjIsIGNvbG9yID0gInJlZCIpKwogIGdlb21fc2YoZGF0YT1kZl9tLCBhbHBoYSA9IDAuMiwgY29sb3IgPSAiYmx1ZSIpKwogIGdlb21fc2YoZGF0YT16b25lcywgYWxwaGEgPSAxLCBjb2xvciA9ICJyZWQiLGZpbGwgPSBOQSwgbHR5ID0gMiwgbHdkID0gNSkrCiAgeGxpbShiYm94W1sieG1pbiJdXSxiYm94W1sieG1heCJdXSkrCiAgeWxpbShiYm94W1sieW1pbiJdXSxiYm94W1sieW1heCJdXSkrCiAgdGhlbWVfY2FydG8KCmdnc2F2ZShoZXJlKCJvdXRjb21lcyIsImFsbC5qcGciKSkKCmJjayArCiNnZ3Bsb3QoKSsgIAogIGdlb21fc2YoZGF0YT1ncmlkLCBjb2xvciA9IGdyYXkoMC41KSxzaXplID0gMC4xLCBmaWxsID0gTkEpKwogIGdlb21fc2YoZGF0YT1idWlsZGluZ3MsIGNvbG9yID0gZ3JheSgwLjUpLHNpemUgPSAwLjQpKwogIGdlb21fc2YoZGF0YT1oZXhiaW5fcywgYWVzKGZpbGwgPSBuYnAsYWxwaGEgPSBuYnApKSsKICAjZ2VvbV9zZihkYXRhPWRmX20sIGFscGhhID0gMC4yLCBjb2xvciA9ICJibHVlIikrCiAgeGxpbShiYm94W1sieG1pbiJdXSxiYm94W1sieG1heCJdXSkrCiAgeWxpbShiYm94W1sieW1pbiJdXSxiYm94W1sieW1heCJdXSkrCiAgdGhlbWVfY2FydG8KCmdnc2F2ZShoZXJlKCJvdXRjb21lcyIsImhleF9zdGF5aW5nLmpwZyIpKQoKYmNrICsKI2dncGxvdCgpKyAgCiAgZ2VvbV9zZihkYXRhPWdyaWQsIGNvbG9yID0gZ3JheSgwLjUpLHNpemUgPSAwLjEsIGZpbGwgPSBOQSkrCiAgZ2VvbV9zZihkYXRhPWJ1aWxkaW5ncywgY29sb3IgPSBncmF5KDAuNSksc2l6ZSA9IDAuNCkrCiAgZ2VvbV9zZihkYXRhPWhleGJpbl9tLCBhZXMoZmlsbCA9IG5icCwgYWxwaGEgPSBuYnApKSsKICAjZ2VvbV9zZihkYXRhPWRmX20sIGFscGhhID0gMC4yLCBjb2xvciA9ICJibHVlIikrCiAgeGxpbShiYm94W1sieG1pbiJdXSxiYm94W1sieG1heCJdXSkrCiAgeWxpbShiYm94W1sieW1pbiJdXSxiYm94W1sieW1heCJdXSkrCiAgdGhlbWVfY2FydG8KCmdnc2F2ZShoZXJlKCJvdXRjb21lcyIsImhleF9tb3ZpbmcuanBnIikpCgpgYGAKCg==